package server;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Encapsulates all necessary operations which have to be done which Auctions.
 * @author Andreas Mair
 */
public class AuctionManager 
{	
	private static AuctionManager instance;
	
	private SimpleDateFormat sdf;
	private NumberFormat nf;
	private HashMap<Integer,Auction> auctions;
	private Timer timer;
	
	private AuctionManager()
	{
		auctions=new HashMap<Integer,Auction>();
		nf=DecimalFormat.getInstance();
		nf.setMaximumFractionDigits(2);
		nf.setMinimumFractionDigits(2);
		sdf=new SimpleDateFormat("dd.MM.yyyy HH:mm z");
		timer=new Timer();
	}
	
	
    public synchronized static AuctionManager getInstance() {
        if(instance==null)
        {
        	instance=new AuctionManager();
        }
    	return instance;
    }	

    /**
     * Returns a String representation of a date in Format "dd.MM.yyyy HH:mm z"
     * @param date
     * @return String representation of date in Format "dd.MM.yyyy HH:mm z"
     */
    public String formatDate(Date date)
    {
    	return sdf.format(date);
    }

    /**
     * Returns a String representation of a long value/100 using 2 fractiondigits
     * @param date
     * @return String representation of a long value/100 using 2 fractiondigits
     */    
    public String formatLong(long value)
    {
    	return nf.format((double)(value/100.00));
    }    
    
	/**
	 * Creates a new Auction 
	 * @param duration long
	 * @param description String
	 * @param owner User
	 * @return created Auction
	 */    
    public synchronized Auction create(long duration,String description,User owner)
    {
    	Auction auction=new Auction(duration,description,owner);
    	synchronized(this)
    	{
    		auctions.put(auction.getiId(), auction);
    		timer.schedule(new AuctionTask(auction.getiId()), duration*1000);
    	}
    	return auction;
    }
    
	/**
	 * Creates a new Auction 
	 * @param auctionId int
	 * @param lPrice long
	 * @param bidder User
	 * @return Auction or null if there is no Auction with auctionId
	 */    
    public synchronized Auction bid(int auctionId,long lPrice,User bidder)
    {
    	Auction auction=this.auctions.get(auctionId);
    	if(auction==null || auction.getdEnd().getTime()<System.currentTimeMillis())
    	{
    		return null;
    	}
    	else
    	{
    		if(auction.getlPrice()<lPrice)
    		{
    			if(auction.getuHighest()!=null && !auction.getuHighest().getStrName().equals(bidder.getStrName()))
    			{
    				UserManager.getInstance().sendUDPMessage(auction.getuHighest(),"!new-bid "+auction.getStrDesc());
    			}
    					
    			auction.setlPrice(lPrice);
    			auction.setuHighest(bidder);
    		}
    		return auction;
    	}
    }
    
    public void finishAuction(int auctionId)
    {
    	Auction auction;
    	synchronized(this)
    	{
    		auction=this.auctions.remove(auctionId);
    	}
    	String strPrice=formatLong(auction.getlPrice());
    	if(auction.getuHighest()!=null)
    	{
    		UserManager.getInstance().sendUDPMessage(auction.getuHighest(), "!auction-ended "+auction.getuHighest().getStrName()+" "+strPrice+" "+auction.getStrDesc());
    		UserManager.getInstance().sendUDPMessage(auction.getuOwner(), "!auction-ended "+auction.getuHighest().getStrName()+" "+strPrice+" "+auction.getStrDesc());
    	}
    	else
    	{
    		UserManager.getInstance().sendUDPMessage(auction.getuOwner(), "!auction-ended none "+strPrice+" "+auction.getStrDesc());
    	}
    }
    
	/**
	 * Lists all Auctions
	 * @return String representation of all Auctions of "No auctions available!"
	 */	
	public synchronized String list()
	{
		if(auctions.size()==0)
		{
			return "No auctions available!";
		}
		else
		{
			String strRet="";
			for(Auction a:auctions.values())
			{
				strRet+=a+"\n";
			}
			return strRet;
		}
	}
	
	/**
	 * Stops the Timer
	 */
	public void stopTimer()
	{
		this.timer.cancel();
	}
	
	private class AuctionTask
	extends TimerTask
	{
		private int auctionId;
	
		public AuctionTask(int auctionId)
		{
			this.auctionId=auctionId;
		}
		@Override
		public void run() 
		{
			finishAuction(auctionId);
			System.out.println("Auction finished '"+auctionId+"'!");
			
		}
	}	
}
